﻿using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using WeShare.WeiXin.Common;
using WeShare.WeiXin.Common.EnumKey;
using WeShare.WeiXin.Mp.Card.Entity;
#if !NET40
using System.Threading.Tasks;
#endif
using static WeShare.WeiXin.Common.OpenApi;
using static WeShare.WeiXin.Common.HttpUtil;
namespace WeShare.WeiXin.Mp.Card
{
    public class CardApi
    {

        /// <summary>
        /// 更改Code接口.确保转赠后的安全性，微信允许自定义Code的商户对已下发的code进行更改。 注：为避免用户疑惑，建议仅在发生转赠行为后（发生转赠后，微信会通过事件推送的方式告知商户被转赠的卡券Code）对用户的Code进行更改。
        /// </summary>
        /// <param name="cardId"></param>
        /// <param name="code"></param>
        /// <param name="newCode"></param>
        /// <param name="tokenOrAppId"></param>
        /// <returns></returns>
        public static BaseRes UpdateCode(string code, string newCode, string cardId, string tokenOrAppId = "")
        {
            var url = $"https://api.weixin.qq.com/card/code/update?access_token={GetToken(tokenOrAppId)}";
            var data = new { code = code, card_id = cardId, new_code = newCode };
            return PostResult<BaseRes>(data, url);
        }
        /// <summary>
        /// 设置卡券失效接口。为满足改票、退款等异常情况，可调用卡券失效接口将用户的卡券设置为失效状态。
        /// </summary>
        /// <param name="code"></param>
        /// <param name="reason">失效理由</param>
        /// <param name="cardId">非自定义code时，此参数可为空</param>
        /// <param name="tokenOrAppId"></param>
        /// <returns></returns>
        public static BaseRes Unavailable(string code, string reason, string cardId = "", string tokenOrAppId = "")
        {
            var url = $"https://api.weixin.qq.com/card/code/unavailable?access_token={GetToken(tokenOrAppId)}";
            var data = new { card_id = cardId, code = code, reason = reason };
            return PostResult<BaseRes>(data, url);
        }
        /// <summary>
        /// 支持开发者调用该接口拉取免费券（优惠券、团购券、折扣券、礼品券）在固定时间区间内的相关数据。
        /// 查询时间区间需小于等于62天
        /// 该接口只能拉取非当天的数据，不能拉取当天的卡券数据，否则报错。
        /// </summary>
        /// <param name="beginDate">查询数据的起始时间。</param>
        /// <param name="endTime">查询数据的截至时间。</param>
        /// <param name="condSource">卡券来源，0为公众平台创建的卡券数据、1是API创建的卡券数据	</param>
        /// <param name="cardId">卡券ID。填写后，指定拉出该卡券的相关数据</param>
        /// <param name="tokenOrAppId"></param>
        /// <returns></returns>
        public static CardBizUinInfoList GetCardBizUinInfoList(DateTime beginDate, DateTime endTime, int condSource,
            string cardId = "", string tokenOrAppId = "")
        {
            var url = $"https://api.weixin.qq.com/datacube/getcardcardinfo?access_token={GetToken(tokenOrAppId)}";
            var data = new { begin_date = beginDate.ToString("yyyy-MM-dd"), end_date = endTime.ToString("yyyy-MM-dd"), cond_source = condSource, card_id = cardId };
            return PostResult<CardBizUinInfoList>(data, url);
        }

        public static MemberCardBizuinInfoList GetCardBizUinInfoList(DateTime beginDate, DateTime endTime, int condSource,
            string tokenOrAppId = "")
        {
            var url = $"https://api.weixin.qq.com/datacube/getcardmembercardinfo?access_token={GetToken(tokenOrAppId)}";
            var data = new { begin_date = beginDate.ToString("yyyy-MM-dd"), end_date = endTime.ToString("yyyy-MM-dd"), cond_source = condSource};
            return PostResult<MemberCardBizuinInfoList>(data, url);
        }
        /// <summary>
        /// 上传卡券所用的图片
        /// 上传的图片限制文件大小限制1MB，仅支持JPG、PNG格式。
        /// </summary>
        /// <param name="filename"></param>
        /// <param name="tokenOrAppId"></param>
        /// <returns></returns>
        public static ImgUrl UploadImg(string filename, string tokenOrAppId = "")
        {
            var url = $"https://api.weixin.qq.com/cgi-bin/media/uploadimg?access_token={OpenApi.GetToken(tokenOrAppId)}";
            var form = new List<FormEntity>
            {
                new FormEntity { IsFile = true, Name = "buffer", Value = filename }
            };
            return HttpUtil.UploadResult<ImgUrl>(url, form);
        }

        /// <summary>
        /// 获取卡券的颜色，默认是从缓存中获取的。由于卡券的颜色值很少变更，所以，为了提高效率，可缓存到内存中。
        /// </summary>
        /// <param name="isfromCache">是否是从缓存中获取。</param>
        /// <param name="tokenOrAppId"></param>
        /// <returns></returns>
        public static CardColors GetColors(bool isfromCache = true, string tokenOrAppId = "")
        {
            CardColors colors = null;
            if (isfromCache)
            {
                colors = CacheService.Get<CardColors>("cardcolors");//CacheHelper.GetValue("cardcolors");
            }
            if (colors == null)
            {
                var url = $"https://api.weixin.qq.com/card/getcolors?access_token={OpenApi.GetToken(tokenOrAppId)}";
                colors = HttpUtil.GetResult<CardColors>(url);
                if (isfromCache)
                {
                    CacheService.Add("cardcolors", colors, 30 * 24 * 1800);
                }
            }
            return colors;
        }
        public static UpdateRes UpdateMemberCard(MemberCard card, string tokenOrAppId = "")
        {
            #region 清空不能更新的字段
            card.card_type = null;
            card.member_card.base_info.brand_name = null;
            card.member_card.base_info.sku = null;
            #endregion
            var url = $"https://api.weixin.qq.com/card/update?access_token={OpenApi.GetToken(tokenOrAppId)}";
            return HttpUtil.PostResult<UpdateRes>(card, url);
        }
        /// <summary>
        /// 创建卡券
        /// </summary>
        /// <param name="card"></param>
        /// <param name="tokenOrAppId"></param>
        /// <returns></returns>
        public static CardIdRes Create<T>(T card, string tokenOrAppId = "") where T : BaseCard, new()
        {
            var url = $"https://api.weixin.qq.com/card/create?access_token={OpenApi.GetToken(tokenOrAppId)}";
            var data = new { card = card };
            return HttpUtil.PostResult<CardIdRes>(data, url);
        }

        /// <summary>
        /// 设置买单接口.card_id已经设置了买单功能，不可变更为自助核销功能
        /// </summary>
        /// <param name="cardId">卡券ID</param>
        /// <param name="isOpen">是否开启买单功能</param>
        /// <param name="tokenOrAppId"></param>
        /// <returns></returns>
        public static BaseRes SetPayCell(string cardId, bool isOpen, string tokenOrAppId = "")
        {
            var url = $"https://api.weixin.qq.com/card/paycell/set?access_token={OpenApi.GetToken(tokenOrAppId)}";
            var data = new { card_id = cardId, is_open = isOpen };
            return HttpUtil.PostResult<BaseRes>(data, url);
        }

        /// <summary>
        /// 设置自助核销.card_id已经设置了买单功能，不可变更为自助核销功能
        /// </summary>
        /// <param name="cardId">卡券ID</param>
        /// <param name="isOpen">是否开启自助核销功能</param>
        /// <param name="needVerifyCode">是否需要输入验证码</param>
        /// <param name="needRemarkAmount">是否需要输入备注金额</param>
        /// <param name="tokenOrAppId"></param>
        /// <returns></returns>
        public static BaseRes SetSelfConsume(string cardId, bool isOpen, bool needVerifyCode = false, bool needRemarkAmount = false, string tokenOrAppId = "")
        {
            var url = $"https://api.weixin.qq.com/card/selfconsumecell/set?access_token={OpenApi.GetToken(tokenOrAppId)}";
            var data = new { card_id = cardId, is_open = isOpen, need_verify_code = needVerifyCode, need_remark_amount = needRemarkAmount };
            return HttpUtil.PostResult<BaseRes>(data, url);
        }
        /// <summary>
        /// 开通券点账户
        /// </summary>
        /// <param name="tokenOrAppId"></param>
        /// <returns></returns>
        public static Reward ActivateCoinAccount(string tokenOrAppId = "")
        {
            var url = $"https://api.weixin.qq.com/card/pay/activate?access_token={OpenApi.GetToken(tokenOrAppId)}";
            return HttpUtil.GetResult<Reward>(url);
            //p8mXIt6yBLyGtjQc7StNXhTE_2MI
        }

        /// <summary>
        /// 提前查询本次新增库存需要多少券点
        /// </summary>
        /// <param name="cardId">需要来配置库存的card_id</param>
        /// <param name="quantity">本次需要兑换的库存数目</param>
        /// <param name="tokenOrAppId"></param>
        /// <returns></returns>
        public static PayPrice GetPayPrice(string cardId, int quantity, string tokenOrAppId = "")
        {
            var url = $"https://api.weixin.qq.com/card/pay/getpayprice?access_token={OpenApi.GetToken(tokenOrAppId)}";
            var data = new
            {
                card_id = cardId,
                quantity = quantity
            };
            return HttpUtil.PostResult<PayPrice>(data, url);
        }
        /// <summary>
        /// 查询券点余额
        /// </summary>
        /// <param name="tokenOrAppId"></param>
        /// <returns></returns>
        public static CoinsInfo GetCoinsInfo(string tokenOrAppId = "")
        {
            var url = $"https://api.weixin.qq.com/card/pay/getcoinsinfo?access_token={OpenApi.GetToken(tokenOrAppId)}";
            return HttpUtil.GetResult<CoinsInfo>(url);
        }

        /// <summary>
        /// 确认兑换库存
        /// </summary>
        /// <param name="cardId">卡券id</param>
        /// <param name="orderId"></param>
        /// <param name="quantity"></param>
        /// <param name="tokenOrAppId"></param>
        /// <returns></returns>
        public static BaseRes ConfirmBuy(string cardId, string orderId, int quantity, string tokenOrAppId = "")
        {
            var url = $"https://api.weixin.qq.com/card/pay/confirm?access_token={OpenApi.GetToken(tokenOrAppId)}";
            var data = new
            {
                card_id = cardId,
                quantity = quantity,
                order_id = orderId
            };
            return HttpUtil.PostResult<BaseRes>(data, url);
        }

        /// <summary>
        /// 充值券点。开发者可以通过此接口为券点账户充值券点，1元等于1点。开发者调用接口后可以获得一个微信支付的支付二维码链接， 开发者可以将链接转化为二维码扫码支付。
        /// </summary>
        /// <param name="coinCount"></param>
        /// <param name="tokenOrAppId"></param>
        /// <returns></returns>
        public static RechargeQr Recharge(int coinCount, string tokenOrAppId = "")
        {
            var url = $"https://api.weixin.qq.com/card/pay/recharge?access_token={OpenApi.GetToken(tokenOrAppId)}";
            var data = new { coin_count = coinCount };
            return HttpUtil.PostResult<RechargeQr>(data, url);
        }

        /// <summary>
        /// 查询充值订单的状态
        /// </summary>
        /// <param name="orderId"></param>
        /// <param name="tokenOrAppId"></param>
        /// <returns></returns>
        public static OrderInfo GetOrderInfo(string orderId, string tokenOrAppId = "")
        {
            var url = $"https://api.weixin.qq.com/card/pay/getorder?access_token={OpenApi.GetToken(tokenOrAppId)}";
            var data = new { order_id = orderId };
            return HttpUtil.PostResult<OrderInfo>(data, url);
        }

        public static OrderList GetOrderList(QueryOrderFilter filter, string tokenOrAppId = "")
        {
            var url = $"https://api.weixin.qq.com/card/pay/getorderlist?access_token={OpenApi.GetToken(tokenOrAppId)}";
            var data = new
            {
                offset = filter.offset,
                count = filter.count,
                order_type = filter.order_type,
                nor_filter = new { status = filter.NorStatus },
                sort_info = new
                {
                    sort_key = filter.sort_key,
                    sort_type = filter.sort_type,
                },
                begin_time = Utils.ConvertDateTimeInt(filter.begin_time),
                end_time = Utils.ConvertDateTimeInt(filter.end_time)
            };
            return HttpUtil.PostResult<OrderList>(data, url);
        }

        #region 投放

        /// <summary>
        /// 创建单卡券的二维码
        /// </summary>
        /// <param name="expire">指定二维码的有效时间，范围是60 ~ 1800秒。不填默认为365天有效</param>
        /// <param name="param">卡券参数</param>
        /// <param name="tokenOrAppId"></param>
        /// <returns></returns>
        public static CardQrRes CreateQr(SingleCardParam param, int? expire = null, string tokenOrAppId = "")
        {
            var data = new
            {
                action_name = "QR_CARD",
                expire_seconds = expire,
                action_info = new
                {
                    card = param
                }
            };
            var url = $"https://api.weixin.qq.com/card/qrcode/create?access_token={OpenApi.GetToken(tokenOrAppId)}";
            return HttpUtil.PostResult<CardQrRes>(data, url);
        }

        /// <summary>
        /// 创建多卡券的二维码。领取多张的二维码一次最多填入5个card_id，否则报错
        /// </summary>
        /// <param name="param">卡券参数</param>
        /// <param name="tokenOrAppId"></param>
        /// <returns></returns>
        public static CardQrRes CreateQr(MultipleCardParam param, string tokenOrAppId = "")
        {
            var data = new
            {
                action_name = "QR_MULTIPLE_CARD",
                action_info = new
                {
                    multiple_card = new
                    {
                        card_list = param
                    }
                }
            };
            var url = $"https://api.weixin.qq.com/card/qrcode/create?access_token={OpenApi.GetToken(tokenOrAppId)}";
            return HttpUtil.PostResult<CardQrRes>(data, url);
        }

        /// <summary>
        /// 创建卡券货架
        /// </summary>
        /// <param name="page">货架参数</param>
        /// <param name="tokenOrAppId"></param>
        /// <returns></returns>
        public static LandingPageRes CreatePage(LandingPage page, string tokenOrAppId = "")
        {
            var url =
                $"https://api.weixin.qq.com/card/landingpage/create?access_token={OpenApi.GetToken(tokenOrAppId)}";
            return HttpUtil.PostResult<LandingPageRes>(page, url);
        }
        #endregion

        #region 自定义code

        /// <summary>
        /// 导入自定义code。
        /// 1）单次调用接口传入code的数量上限为100个。
        /// 2）每一个 code 均不能为空串。
        /// 3）导入结束后系统会自动判断提供方设置库存与实际导入code的量是否一致。
        /// 4）导入失败支持重复导入，提示成功为止。
        /// </summary>
        /// <param name="cardId">卡券id</param>
        /// <param name="codes">自定义code列表</param>
        /// <param name="tokenOrAppId"></param>
        /// <returns></returns>
        public static ImportCodeRes ImportCode(string cardId, List<string> codes, string tokenOrAppId = "")
        {
            var url = $"http://api.weixin.qq.com/card/code/deposit?access_token={OpenApi.GetToken(tokenOrAppId)}";
            var data = new { card_id = cardId, code = codes };
            return HttpUtil.PostResult<ImportCodeRes>(data, url);
        }

        public static CheckCodeRes CheckCode(string cardId, List<string> codes, string tokenOrAppId = "")
        {
            var url = $"http://api.weixin.qq.com/card/code/checkcode?access_token={OpenApi.GetToken(tokenOrAppId)}";
            var data = new { card_id = cardId, code = codes };
            return HttpUtil.PostResult<CheckCodeRes>(data, url);
        }

        /// <summary>
        /// 查询导入成功的数量
        /// </summary>
        /// <param name="cardId">卡券id</param>
        /// <param name="tokenOrAppId"></param>
        /// <returns></returns>
        public static CodeCount QueryCodeCount(string cardId, string tokenOrAppId = "")
        {
            var url =
                $"http://api.weixin.qq.com/card/code/getdepositcount?access_token={OpenApi.GetToken(tokenOrAppId)}";
            var data = new { card_id = cardId };
            return HttpUtil.PostResult<CodeCount>(data, url);
        }

        /// <summary>
        /// 生成可将卡券嵌入图文消息的html。
        /// </summary>
        /// <param name="cardId">卡券id</param>
        /// <param name="tokenOrAppId"></param>
        /// <returns></returns>
        public static MpNewContent GetHtml(string cardId, string tokenOrAppId = "")
        {
            var url = $"https://api.weixin.qq.com/card/mpnews/gethtml?access_token={OpenApi.GetToken(tokenOrAppId)}";
            var data = new { card_id = cardId };
            return HttpUtil.PostResult<MpNewContent>(data, url);
        }
        #endregion

        /// <summary>
        /// 设置卡券测试白名单
        /// </summary>
        /// <param name="openid">openid列表</param>
        /// <param name="username">微信号列表。与openid列表不能同时为空</param>
        /// <param name="tokenOrAppId"></param>
        /// <returns></returns>
        public static BaseRes SetTestWhiteList(List<string> openid = null, List<string> username = null, string tokenOrAppId = "")
        {
            var url = $"https://api.weixin.qq.com/card/testwhitelist/set?access_token={OpenApi.GetToken(tokenOrAppId)}";
            var data = new { openid = openid, username = username };
            return HttpUtil.PostResult<BaseRes>(data, url);
        }
        /// <summary>
        /// 删除卡券
        /// </summary>
        /// <param name="cardId"></param>
        /// <param name="tokenOrAppId"></param>
        /// <returns></returns>
        public static BaseRes Delete(string cardId, string tokenOrAppId = "")
        {
            var url = $"https://api.weixin.qq.com/card/delete?access_token={OpenApi.GetToken(tokenOrAppId)}";
            var data = new { card_id = cardId };
            return HttpUtil.PostResult<BaseRes>(data, url);
        }

        #region 核销

        /// <summary>
        /// 查询code
        /// </summary>
        /// <param name="code"></param>
        /// <param name="checkConsume"></param>
        /// <param name="cardId"></param>
        /// <param name="tokenOrAppId"></param>
        /// <returns></returns>
        public static CodeInfoRes QueryCode(string code, bool? checkConsume = null, string cardId = null, string tokenOrAppId = "")
        {
            var url = $"https://api.weixin.qq.com/card/code/get?access_token={OpenApi.GetToken(tokenOrAppId)}";
            var data = new
            {
                card_id = cardId,
                code = code,
                check_consume = true
            };
            return HttpUtil.PostResult<CodeInfoRes>(data, url);
        }

        /// <summary>
        /// 核销卡券
        /// </summary>
        /// <param name="code"></param>
        /// <param name="cardId">卡券ID。创建卡券时use_custom_code填写true时必填。非自定义Code不必填写。</param>
        /// <param name="tokenOrAppId"></param>
        /// <returns></returns>
        public static ConsumeRes Comsume(string code, string cardId = null, string tokenOrAppId = "")
        {
            var url = $"https://api.weixin.qq.com/card/code/consume?access_token={OpenApi.GetToken(tokenOrAppId)}";
            var data = new
            {
                card_id = cardId,
                code = code
            };
            return HttpUtil.PostResult<ConsumeRes>(data, url);
        }

        /// <summary>
        /// code解密。开发者若从url上获取到加密code,请注意先进行urldecode，否则报错。
        /// </summary>
        /// <param name="encryptCode">经过加密的Code码。</param>
        /// <param name="tokenOrAppId"></param>
        /// <returns></returns>
        public static DecryptCodeRes DecryptCode(string encryptCode, string tokenOrAppId = "")
        {
            var url = $"https://api.weixin.qq.com/card/code/decrypt?access_token={OpenApi.GetToken(tokenOrAppId)}";
            var data = new { encrypt_code = encryptCode };
            return HttpUtil.PostResult<DecryptCodeRes>(data, url);
        }

        /// <summary>
        /// 获取用户所有的卡券列表
        /// </summary>
        /// <param name="openId"></param>
        /// <param name="cardId"></param>
        /// <param name="tokenOrAppId"></param>
        /// <returns></returns>
        public static CardListByOpenIdRes GetCardListByOpenId(string openId, string cardId, string tokenOrAppId = "")
        {
            var url = $"https://api.weixin.qq.com/card/user/getcardlist?access_token={OpenApi.GetToken(tokenOrAppId)}";
            var data = new { openid = openId, card_id = cardId };
            return HttpUtil.PostResult<CardListByOpenIdRes>(data, url);
        }

        /// <summary>
        /// 获取卡券信息
        /// </summary>
        /// <param name="cardId"></param>
        /// <param name="tokenOrAppId"></param>
        /// <returns></returns>
        public static CardInfoRes GetCardInfo(string cardId, string tokenOrAppId = "")
        {
            var url = $"https://api.weixin.qq.com/card/get?access_token={OpenApi.GetToken(tokenOrAppId)}";
            var data = new { card_id = cardId };
            JObject obj = HttpUtil.PostResult<JObject>(data, url);
            CardInfoRes res = new CardInfoRes();
            res.errcode = obj.Value<int>("errcode");
            if (res.errcode == 0)
            {
                var type = obj["card"]["card_type"].Value<string>();
                var card = obj["card"];
                switch (type)
                {
                    case "DISCOUNT":
                        res.card = card.ToObject<DiscountCard>(); break;
                    case "CASH":
                        res.card = card.ToObject<CashCard>();
                        break;
                    case "GROUPON":
                        res.card = card.ToObject<GrouponCard>(); break;
                    case "GIFT":
                        res.card = card.ToObject<GiftCard>(); break;
                    case "GENERALCOUPON":
                        res.card = card.ToObject<GeneralCouponCard>(); break;
                    case "MEMBER_CARD":
                    case "SCENIC_TICKET":
                    case "MOVIE_TICKET":
                    case "BOARDING_PASS":
                    case "BUS_TICKET":
                    case "MEETING_TICKET":
                    //res.card = card.ToObject<Mem>();break;
                    default:
                        break;
                }
            }
            else
            {
                res.errmsg = obj.Value<string>("errmsg");
            }
            return res;
        }

        /// <summary>
        /// 根据状态，查询卡券的列表
        /// </summary>
        /// <param name="offset">查询卡列表的起始偏移量，从0开始，即offset: 5是指从从列表里的第六个开始读取。</param>
        /// <param name="count">需要查询的卡片的数量（数量最大50）。</param>
        /// <param name="status"></param>
        /// <param name="tokenOrAppId"></param>
        /// <returns></returns>
        public static CardListByStatusRes QueryCardListByStatus(int offset, int count, List<CardStatus> status = null, string tokenOrAppId = "")
        {
            var url = $"https://api.weixin.qq.com/card/batchget?access_token={tokenOrAppId}";
            var data = new { offset = offset, count = count, status_list = status };
            return HttpUtil.PostResult<CardListByStatusRes>(data, url);
        }

        ///  <summary>
        ///  更新卡券信息
        ///  1. 请开发者注意需要重新提审的字段，开发者调用更新接口时，若传入了提审字段则卡券需要重新进入审核状态；
        /// 2. 接口更新方式为覆盖更新：即开发者只需传入需要更改的字段，其他字段无需填入，否则可能导致卡券重新提审；
        /// 3. 若开发者置空某些字段，可直接在更新时传“”（空）；
        ///  </summary>
        ///  <param name="card"></param>
        /// <param name="tokenOrAppId"></param>
        /// <returns></returns>
        public static UpdateRes Update(string cardId, EditableInfo card, string tokenOrAppId = "")
        {
            var type = card.GetType().Name;
            var data = new CardEnumObject
            {
                card_id = cardId,
            };
            switch (type)
            {
                case "EditableMember":
                    data.member_card = (EditableMember)card;
                    break;
                case "EditableGroupon":
                    data.groupon = (EditableGroupon)card;
                    break;

                case "EditableCash":
                    data.cash = (EditableCash)card;
                    break;
                case "EditableDiscount":
                    data.discount = (EditableDiscount)card;
                    break;
                case "EditableGift":
                    data.gift = (EditableGift)card;
                    break;
                case "EditableGeneralCoupon":
                    data.general_coupon = (EditableGeneralCoupon)card;
                    break;
                case "EditableMeetingTicket":
                    data.meeting_ticket = (EditableMeetingTicket)card;
                    break;
                case "EditableScenicTicket":
                    data.scenic_ticket = (EditableScenicTicket)card;
                    break;
                case "EditableMovie":
                    data.movie_ticket = (EditableMovie)card;
                    break;
                case "EditableBoardingPass":
                    data.boarding_pass = (EditableBoardingPass)card;
                    break;
            }
            var url = $"https://api.weixin.qq.com/card/update?access_token={OpenApi.GetToken(tokenOrAppId)}";
            return HttpUtil.PostResult<UpdateRes>(data, url);
        }

        /// <summary>
        /// 修改库存
        /// </summary>
        /// <param name="cardId">卡券ID</param>
        /// <param name="value">要增加或者减少的库存数量。正数为增加</param>
        /// <param name="tokenOrAppId"></param>
        /// <returns></returns>
        public static BaseRes UpdateStock(string cardId, int value, string tokenOrAppId = "")
        {
            var url = $"https://api.weixin.qq.com/card/modifystock?access_token={OpenApi.GetToken(tokenOrAppId)}";
            int increaseValue = 0;
            int reduceValue = 0;
            if (value > 0)
            {
                increaseValue = value;
            }
            else
            {
                reduceValue = value * -1;
            }
            var data = new { card_id = cardId, increase_stock_value = increaseValue, reduce_stock_value = reduceValue };
            return HttpUtil.PostResult<BaseRes>(data, url);
        }
        #endregion

        #region 会员卡相关接口

        /// <summary>
        /// 会员卡接口激活
        /// </summary>
        /// <param name="param"></param>
        /// <param name="tokenOrAppId"></param>
        /// <returns></returns>
        public static BaseRes MemberCardActivate(ActivateParam param, string tokenOrAppId = "")
        {
            var url =
                $"https://api.weixin.qq.com/card/membercard/activate?access_token={OpenApi.GetToken(tokenOrAppId)}";
            return HttpUtil.PostResult<BaseRes>(param, url);
        }

        /// <summary>
        /// 一键激活设置激活字段
        /// </summary>
        /// <param name="accessToken"></param>
        /// <param name="param"></param>
        /// <param name="tokenOrAppId"></param>
        /// <returns></returns>
        public static BaseRes SetActivateForm(ActiveForm param, string tokenOrAppId = "")
        {
            var url =
                $"https://api.weixin.qq.com/card/membercard/activateuserform/set?access_token={OpenApi.GetToken(tokenOrAppId)}";
            return HttpUtil.PostResult<BaseRes>(param, url);
        }
        /// <summary>
        /// 拉取会员信息接口
        /// </summary>
        /// <param name="cardId"></param>
        /// <param name="code"></param>
        /// <param name="tokenOrAppId"></param>
        /// <returns></returns>
        public static UserInfoRes GetMemberInfo(string cardId, string code, string tokenOrAppId = "")
        {
            var url =
                $"https://api.weixin.qq.com/card/membercard/userinfo/get?access_token={OpenApi.GetToken(tokenOrAppId)}";
            var data = new { card_id = cardId, code = code };
            return HttpUtil.PostResult<UserInfoRes>(data, url);
        }
        /// <summary>
        /// 跳转型一键激活，第三步，获取用户提交资料
        /// </summary>
        /// <param name="activateTicket"></param>
        /// <param name="tokenOrAppId"></param>
        /// <returns></returns>
        public static ActivateTempInfo GetActivateTempInfo(string activateTicket, string tokenOrAppId = "")
        {
            var url =
                $"https://api.weixin.qq.com/card/membercard/activatetempinfo/get?access_token={OpenApi.GetToken(tokenOrAppId)}";
            var data = new { activate_ticket = activateTicket };
            return HttpUtil.PostResult<ActivateTempInfo>(data, url);
        }

        /// <summary>
        /// 更新会员信息
        /// </summary>
        /// <param name="param"></param>
        /// <param name="tokenOrAppId"></param>
        /// <returns></returns>
        public static UpdateMemberRes UpdateMemberInfo(UpdateParam param, string tokenOrAppId = "")
        {
            var url =
                $"https://api.weixin.qq.com/card/membercard/updateuser?access_token={OpenApi.GetToken(tokenOrAppId)}";
            return HttpUtil.PostResult<UpdateMemberRes>(param, url);
        }
        #endregion


#if !NET40
        /// <summary>
        /// 上传卡券所用的图片
        /// 上传的图片限制文件大小限制1MB，仅支持JPG、PNG格式。
        /// </summary>
        /// <param name="filename"></param>
        /// <param name="tokenOrAppId"></param>
        /// <returns></returns>
        public static async Task<ImgUrl> UploadImgAsync(string filename, string tokenOrAppId = "")
        {
            var url = $"https://api.weixin.qq.com/cgi-bin/media/uploadimg?access_token={await OpenApi.GetTokenAsync(tokenOrAppId)}";
            var form = new List<FormEntity>
            {
                new FormEntity { IsFile = true, Name = "buffer", Value = filename }
            };
            return await HttpUtil.UploadResultAsync<ImgUrl>(url, form);
        }

        /// <summary>
        /// 获取卡券的颜色，默认是从缓存中获取的。由于卡券的颜色值很少变更，所以，为了提高效率，可缓存到内存中。
        /// </summary>
        /// <param name="isfromCache">是否是从缓存中获取。</param>
        /// <param name="tokenOrAppId"></param>
        /// <returns></returns>
        public static async Task<CardColors> GetColorsAsync(bool isfromCache = true, string tokenOrAppId = "")
        {
            CardColors colors = null;
            if (isfromCache)
            {
                colors = CacheService.Get<CardColors>("cardcolors");//CacheHelper.GetValue("cardcolors");
            }
            if (colors == null)
            {
                var url = $"https://api.weixin.qq.com/card/getcolors?access_token={await OpenApi.GetTokenAsync(tokenOrAppId)}";
                colors = await HttpUtil.GetResultAsync<CardColors>(url);
                if (isfromCache)
                {
                    CacheService.Add("cardcolors", colors, 30 * 24 * 1800);
                }
            }
            return colors;
        }
        public static async Task<UpdateRes> UpdateMemberCardAsync(MemberCard card, string tokenOrAppId = "")
        {
            #region 清空不能更新的字段
            card.card_type = null;
            card.member_card.base_info.brand_name = null;
            card.member_card.base_info.sku = null;
            #endregion
            var url = $"https://api.weixin.qq.com/card/update?access_token={await OpenApi.GetTokenAsync(tokenOrAppId)}";
            return await HttpUtil.PostResultAsync<UpdateRes>(card, url);
        }
        /// <summary>
        /// 创建卡券
        /// </summary>
        /// <param name="card"></param>
        /// <param name="tokenOrAppId"></param>
        /// <returns></returns>
        public static async Task<CardIdRes> CreateAsync<T>(T card, string tokenOrAppId = "") where T : BaseCard, new()
        {
            var url = $"https://api.weixin.qq.com/card/create?access_token={await OpenApi.GetTokenAsync(tokenOrAppId)}";
            var data = new { card = card };
            return await HttpUtil.PostResultAsync<CardIdRes>(data, url);
        }

        /// <summary>
        /// 设置买单接口.card_id已经设置了买单功能，不可变更为自助核销功能
        /// </summary>
        /// <param name="cardId">卡券ID</param>
        /// <param name="isOpen">是否开启买单功能</param>
        /// <param name="tokenOrAppId"></param>
        /// <returns></returns>
        public static async Task<BaseRes> SetPayCellAsync(string cardId, bool isOpen, string tokenOrAppId = "")
        {
            var url = $"https://api.weixin.qq.com/card/paycell/set?access_token={await OpenApi.GetTokenAsync(tokenOrAppId)}";
            var data = new { card_id = cardId, is_open = isOpen };
            return await HttpUtil.PostResultAsync<BaseRes>(data, url);
        }

        /// <summary>
        /// 设置自助核销.card_id已经设置了买单功能，不可变更为自助核销功能
        /// </summary>
        /// <param name="cardId">卡券ID</param>
        /// <param name="isOpen">是否开启自助核销功能</param>
        /// <param name="needVerifyCode">是否需要输入验证码</param>
        /// <param name="needRemarkAmount">是否需要输入备注金额</param>
        /// <param name="tokenOrAppId"></param>
        /// <returns></returns>
        public static async Task<BaseRes> SetSelfConsumeAsync(string cardId, bool isOpen, bool needVerifyCode = false, bool needRemarkAmount = false, string tokenOrAppId = "")
        {
            var url = $"https://api.weixin.qq.com/card/selfconsumecell/set?access_token={await OpenApi.GetTokenAsync(tokenOrAppId)}";
            var data = new { card_id = cardId, is_open = isOpen, need_verify_code = needVerifyCode, need_remark_amount = needRemarkAmount };
            return await HttpUtil.PostResultAsync<BaseRes>(data, url);
        }
        /// <summary>
        /// 开通券点账户
        /// </summary>
        /// <param name="tokenOrAppId"></param>
        /// <returns></returns>
        public static async Task<Reward> ActivateCoinAccountAsync(string tokenOrAppId = "")
        {
            var url = $"https://api.weixin.qq.com/card/pay/activate?access_token={await OpenApi.GetTokenAsync(tokenOrAppId)}";
            return await HttpUtil.GetResultAsync<Reward>(url);
        }

        /// <summary>
        /// 提前查询本次新增库存需要多少券点
        /// </summary>
        /// <param name="cardId">需要来配置库存的card_id</param>
        /// <param name="quantity">本次需要兑换的库存数目</param>
        /// <param name="tokenOrAppId"></param>
        /// <returns></returns>
        public static async Task<PayPrice> GetPayPriceAsync(string cardId, int quantity, string tokenOrAppId = "")
        {
            var url = $"https://api.weixin.qq.com/card/pay/getpayprice?access_token={await OpenApi.GetTokenAsync(tokenOrAppId)}";
            var data = new
            {
                card_id = cardId,
                quantity = quantity
            };
            return await HttpUtil.PostResultAsync<PayPrice>(data, url);
        }
        /// <summary>
        /// 查询券点余额
        /// </summary>
        /// <param name="tokenOrAppId"></param>
        /// <returns></returns>
        public static async Task<CoinsInfo> GetCoinsInfoAsync(string tokenOrAppId = "")
        {
            var url = $"https://api.weixin.qq.com/card/pay/getcoinsinfo?access_token={await OpenApi.GetTokenAsync(tokenOrAppId)}";
            return await HttpUtil.GetResultAsync<CoinsInfo>(url);
        }

        /// <summary>
        /// 确认兑换库存
        /// </summary>
        /// <param name="cardId">卡券id</param>
        /// <param name="orderId"></param>
        /// <param name="quantity"></param>
        /// <param name="tokenOrAppId"></param>
        /// <returns></returns>
        public static async Task<BaseRes> ConfirmBuyAsync(string cardId, string orderId, int quantity, string tokenOrAppId = "")
        {
            var url = $"https://api.weixin.qq.com/card/pay/confirm?access_token={await OpenApi.GetTokenAsync(tokenOrAppId)}";
            var data = new
            {
                card_id = cardId,
                quantity = quantity,
                order_id = orderId
            };
            return await HttpUtil.PostResultAsync<BaseRes>(data, url);
        }

        /// <summary>
        /// 充值券点。开发者可以通过此接口为券点账户充值券点，1元等于1点。开发者调用接口后可以获得一个微信支付的支付二维码链接， 开发者可以将链接转化为二维码扫码支付。
        /// </summary>
        /// <param name="coinCount"></param>
        /// <param name="tokenOrAppId"></param>
        /// <returns></returns>
        public static async Task<RechargeQr> RechargeAsync(int coinCount, string tokenOrAppId = "")
        {
            var url = $"https://api.weixin.qq.com/card/pay/recharge?access_token={await OpenApi.GetTokenAsync(tokenOrAppId)}";
            var data = new { coin_count = coinCount };
            return await HttpUtil.PostResultAsync<RechargeQr>(data, url);
        }

        /// <summary>
        /// 查询充值订单的状态
        /// </summary>
        /// <param name="orderId"></param>
        /// <param name="tokenOrAppId"></param>
        /// <returns></returns>
        public static async Task<OrderInfo> GetOrderInfoAsync(string orderId, string tokenOrAppId = "")
        {
            var url = $"https://api.weixin.qq.com/card/pay/getorder?access_token={await OpenApi.GetTokenAsync(tokenOrAppId)}";
            var data = new { order_id = orderId };
            return await HttpUtil.PostResultAsync<OrderInfo>(data, url);
        }

        public static async Task<OrderList> GetOrderListAsync(QueryOrderFilter filter, string tokenOrAppId = "")
        {
            var url = $"https://api.weixin.qq.com/card/pay/getorderlist?access_token={await OpenApi.GetTokenAsync(tokenOrAppId)}";
            var data = new
            {
                offset = filter.offset,
                count = filter.count,
                order_type = filter.order_type,
                nor_filter = new { status = filter.NorStatus },
                sort_info = new
                {
                    sort_key = filter.sort_key,
                    sort_type = filter.sort_type,
                },
                begin_time = Utils.ConvertDateTimeInt(filter.begin_time),
                end_time = Utils.ConvertDateTimeInt(filter.end_time)
            };
            return await HttpUtil.PostResultAsync<OrderList>(data, url);
        }

        #region 投放

        /// <summary>
        /// 创建单卡券的二维码
        /// </summary>
        /// <param name="expire">指定二维码的有效时间，范围是60 ~ 1800秒。不填默认为365天有效</param>
        /// <param name="param">卡券参数</param>
        /// <param name="tokenOrAppId"></param>
        /// <returns></returns>
        public static async Task<CardQrRes> CreateQrAsync(SingleCardParam param, int? expire = null, string tokenOrAppId = "")
        {
            var data = new
            {
                action_name = "QR_CARD",
                expire_seconds = expire,
                action_info = new
                {
                    card = param
                }
            };
            var url = $"https://api.weixin.qq.com/card/qrcode/create?access_token={await OpenApi.GetTokenAsync(tokenOrAppId)}";
            return await HttpUtil.PostResultAsync<CardQrRes>(data, url);
        }

        /// <summary>
        /// 创建多卡券的二维码。领取多张的二维码一次最多填入5个card_id，否则报错
        /// </summary>
        /// <param name="param">卡券参数</param>
        /// <param name="tokenOrAppId"></param>
        /// <returns></returns>
        public static async Task<CardQrRes> CreateQrAsync(MultipleCardParam param, string tokenOrAppId = "")
        {
            var data = new
            {
                action_name = "QR_MULTIPLE_CARD",
                action_info = new
                {
                    multiple_card = new
                    {
                        card_list = param
                    }
                }
            };
            var url = $"https://api.weixin.qq.com/card/qrcode/create?access_token={await OpenApi.GetTokenAsync(tokenOrAppId)}";
            return await HttpUtil.PostResultAsync<CardQrRes>(data, url);
        }

        /// <summary>
        /// 创建卡券货架
        /// </summary>
        /// <param name="page">货架参数</param>
        /// <param name="tokenOrAppId"></param>
        /// <returns></returns>
        public static async Task<LandingPageRes> CreatePageAsync(LandingPage page, string tokenOrAppId = "")
        {
            var url =
                $"https://api.weixin.qq.com/card/landingpage/create?access_token={await OpenApi.GetTokenAsync(tokenOrAppId)}";
            return await HttpUtil.PostResultAsync<LandingPageRes>(page, url);
        }
        #endregion

        #region 自定义code

        /// <summary>
        /// 导入自定义code。
        /// 1）单次调用接口传入code的数量上限为100个。
        /// 2）每一个 code 均不能为空串。
        /// 3）导入结束后系统会自动判断提供方设置库存与实际导入code的量是否一致。
        /// 4）导入失败支持重复导入，提示成功为止。
        /// </summary>
        /// <param name="cardId">卡券id</param>
        /// <param name="codes">自定义code列表</param>
        /// <param name="tokenOrAppId"></param>
        /// <returns></returns>
        public static async Task<ImportCodeRes> ImportCodeAsync(string cardId, List<string> codes, string tokenOrAppId = "")
        {
            var url = $"http://api.weixin.qq.com/card/code/deposit?access_token={await OpenApi.GetTokenAsync(tokenOrAppId)}";
            var data = new { card_id = cardId, code = codes };
            return await HttpUtil.PostResultAsync<ImportCodeRes>(data, url);
        }

        public static async Task<CheckCodeRes> CheckCodeAsync(string cardId, List<string> codes, string tokenOrAppId = "")
        {
            var url = $"http://api.weixin.qq.com/card/code/checkcode?access_token={await OpenApi.GetTokenAsync(tokenOrAppId)}";
            var data = new { card_id = cardId, code = codes };
            return await HttpUtil.PostResultAsync<CheckCodeRes>(data, url);
        }

        /// <summary>
        /// 查询导入成功的数量
        /// </summary>
        /// <param name="cardId">卡券id</param>
        /// <param name="tokenOrAppId"></param>
        /// <returns></returns>
        public static async Task<CodeCount> QueryCodeCountAsync(string cardId, string tokenOrAppId = "")
        {
            var url =
                $"http://api.weixin.qq.com/card/code/getdepositcount?access_token={await OpenApi.GetTokenAsync(tokenOrAppId)}";
            var data = new { card_id = cardId };
            return await HttpUtil.PostResultAsync<CodeCount>(data, url);
        }

        /// <summary>
        /// 生成可将卡券嵌入图文消息的html。
        /// </summary>
        /// <param name="cardId">卡券id</param>
        /// <param name="tokenOrAppId"></param>
        /// <returns></returns>
        public static async Task<MpNewContent> GetHtmlAsync(string cardId, string tokenOrAppId = "")
        {
            var url = $"https://api.weixin.qq.com/card/mpnews/gethtml?access_token={await OpenApi.GetTokenAsync(tokenOrAppId)}";
            var data = new { card_id = cardId };
            return await HttpUtil.PostResultAsync<MpNewContent>(data, url);
        }
        #endregion

        /// <summary>
        /// 设置卡券测试白名单
        /// </summary>
        /// <param name="openid">openid列表</param>
        /// <param name="username">微信号列表。与openid列表不能同时为空</param>
        /// <param name="tokenOrAppId"></param>
        /// <returns></returns>
        public static async Task<BaseRes> SetTestWhiteListAsync(List<string> openid = null, List<string> username = null, string tokenOrAppId = "")
        {
            var url = $"https://api.weixin.qq.com/card/testwhitelist/set?access_token={await OpenApi.GetTokenAsync(tokenOrAppId)}";
            var data = new { openid = openid, username = username };
            return await HttpUtil.PostResultAsync<BaseRes>(data, url);
        }
        /// <summary>
        /// 删除卡券
        /// </summary>
        /// <param name="cardId"></param>
        /// <param name="tokenOrAppId"></param>
        /// <returns></returns>
        public static async Task<BaseRes> DeleteAsync(string cardId, string tokenOrAppId = "")
        {
            var url = $"https://api.weixin.qq.com/card/delete?access_token={await OpenApi.GetTokenAsync(tokenOrAppId)}";
            var data = new { card_id = cardId };
            return await HttpUtil.PostResultAsync<BaseRes>(data, url);
        }

        #region 核销

        /// <summary>
        /// 查询code
        /// </summary>
        /// <param name="code"></param>
        /// <param name="checkConsume"></param>
        /// <param name="cardId"></param>
        /// <param name="tokenOrAppId"></param>
        /// <returns></returns>
        public static async Task<CodeInfoRes> QueryCodeAsync(string code, bool? checkConsume = null, string cardId = null, string tokenOrAppId = "")
        {
            var url = $"https://api.weixin.qq.com/card/code/get?access_token={await OpenApi.GetTokenAsync(tokenOrAppId)}";
            var data = new
            {
                card_id = cardId,
                code = code,
                check_consume = true
            };
            return await HttpUtil.PostResultAsync<CodeInfoRes>(data, url);
        }

        /// <summary>
        /// 核销卡券
        /// </summary>
        /// <param name="code"></param>
        /// <param name="cardId">卡券ID。创建卡券时use_custom_code填写true时必填。非自定义Code不必填写。</param>
        /// <param name="tokenOrAppId"></param>
        /// <returns></returns>
        public static async Task<ConsumeRes> ComsumeAsync(string code, string cardId = null, string tokenOrAppId = "")
        {
            var url = $"https://api.weixin.qq.com/card/code/consume?access_token={await OpenApi.GetTokenAsync(tokenOrAppId)}";
            var data = new
            {
                card_id = cardId,
                code = code
            };
            return await HttpUtil.PostResultAsync<ConsumeRes>(data, url);
        }

        /// <summary>
        /// code解密。开发者若从url上获取到加密code,请注意先进行urldecode，否则报错。
        /// </summary>
        /// <param name="encryptCode">经过加密的Code码。</param>
        /// <param name="tokenOrAppId"></param>
        /// <returns></returns>
        public static async Task<DecryptCodeRes> DecryptCodeAsync(string encryptCode, string tokenOrAppId = "")
        {
            var url = $"https://api.weixin.qq.com/card/code/decrypt?access_token={await OpenApi.GetTokenAsync(tokenOrAppId)}";
            var data = new { encrypt_code = encryptCode };
            return await HttpUtil.PostResultAsync<DecryptCodeRes>(data, url);
        }

        /// <summary>
        /// 获取用户所有的卡券列表
        /// </summary>
        /// <param name="openId"></param>
        /// <param name="cardId"></param>
        /// <param name="tokenOrAppId"></param>
        /// <returns></returns>
        public static async Task<CardListByOpenIdRes> GetCardListByOpenIdAsync(string openId, string cardId, string tokenOrAppId = "")
        {
            var url = $"https://api.weixin.qq.com/card/user/getcardlist?access_token={await OpenApi.GetTokenAsync(tokenOrAppId)}";
            var data = new { openid = openId, card_id = cardId };
            return await HttpUtil.PostResultAsync<CardListByOpenIdRes>(data, url);
        }

        /// <summary>
        /// 获取卡券信息
        /// </summary>
        /// <param name="cardId"></param>
        /// <param name="tokenOrAppId"></param>
        /// <returns></returns>
        public static async Task<CardInfoRes> GetCardInfoAsync(string cardId, string tokenOrAppId = "")
        {
            var url = $"https://api.weixin.qq.com/card/get?access_token={await OpenApi.GetTokenAsync(tokenOrAppId)}";
            var data = new { card_id = cardId };
            JObject obj = await HttpUtil.PostResultAsync<JObject>(data, url);
            CardInfoRes res = new CardInfoRes();
            res.errcode = obj.Value<int>("errcode");
            if (res.errcode == 0)
            {
                var type = obj["card"]["card_type"].Value<string>();
                var card = obj["card"];
                switch (type)
                {
                    case "DISCOUNT":
                        res.card = card.ToObject<DiscountCard>(); break;
                    case "CASH":
                        res.card = card.ToObject<CashCard>();
                        break;
                    case "GROUPON":
                        res.card = card.ToObject<GrouponCard>(); break;
                    case "GIFT":
                        res.card = card.ToObject<GiftCard>(); break;
                    case "GENERALCOUPON":
                        res.card = card.ToObject<GeneralCouponCard>(); break;
                    case "MEMBER_CARD":
                    case "SCENIC_TICKET":
                    case "MOVIE_TICKET":
                    case "BOARDING_PASS":
                    case "BUS_TICKET":
                    case "MEETING_TICKET":
                    //res.card = card.ToObject<Mem>();break;
                    default:
                        break;
                }
            }
            else
            {
                res.errmsg = obj.Value<string>("errmsg");
            }
            return res;
        }

        /// <summary>
        /// 根据状态，查询卡券的列表
        /// </summary>
        /// <param name="offset">查询卡列表的起始偏移量，从0开始，即offset: 5是指从从列表里的第六个开始读取。</param>
        /// <param name="count">需要查询的卡片的数量（数量最大50）。</param>
        /// <param name="status"></param>
        /// <param name="tokenOrAppId"></param>
        /// <returns></returns>
        public static async Task<CardListByStatusRes> QueryCardListByStatusAsync(int offset, int count, List<CardStatus> status = null, string tokenOrAppId = "")
        {
            var url = $"https://api.weixin.qq.com/card/batchget?access_token={tokenOrAppId}";
            var data = new { offset = offset, count = count, status_list = status };
            return await HttpUtil.PostResultAsync<CardListByStatusRes>(data, url);
        }

        ///  <summary>
        ///  更新卡券信息
        ///  1. 请开发者注意需要重新提审的字段，开发者调用更新接口时，若传入了提审字段则卡券需要重新进入审核状态；
        /// 2. 接口更新方式为覆盖更新：即开发者只需传入需要更改的字段，其他字段无需填入，否则可能导致卡券重新提审；
        /// 3. 若开发者置空某些字段，可直接在更新时传“”（空）；
        ///  </summary>
        ///  <param name="card"></param>
        /// <param name="tokenOrAppId"></param>
        /// <returns></returns>
        public static async Task<UpdateRes> UpdateAsync(BaseCard card, string tokenOrAppId = "")
        {
            var url = $"https://api.weixin.qq.com/card/update?access_token={await OpenApi.GetTokenAsync(tokenOrAppId)}";
            return await HttpUtil.PostResultAsync<UpdateRes>(card, url);
        }

        /// <summary>
        /// 修改库存
        /// </summary>
        /// <param name="cardId">卡券ID</param>
        /// <param name="value">要增加或者减少的库存数量。正数为增加</param>
        /// <param name="tokenOrAppId"></param>
        /// <returns></returns>
        public static async Task<BaseRes> UpdateStockAsync(string cardId, int value, string tokenOrAppId = "")
        {
            var url = $"https://api.weixin.qq.com/card/modifystock?access_token={await OpenApi.GetTokenAsync(tokenOrAppId)}";
            int increaseValue = 0;
            int reduceValue = 0;
            if (value > 0)
            {
                increaseValue = value;
            }
            else
            {
                reduceValue = value * -1;
            }
            var data = new { card_id = cardId, increase_stock_value = increaseValue, reduce_stock_value = reduceValue };
            return await HttpUtil.PostResultAsync<BaseRes>(data, url);
        }
        #endregion

        #region 会员卡相关接口

        /// <summary>
        /// 会员卡接口激活
        /// </summary>
        /// <param name="param"></param>
        /// <param name="tokenOrAppId"></param>
        /// <returns></returns>
        public static async Task<BaseRes> MemberCardActivateAsync(ActivateParam param, string tokenOrAppId = "")
        {
            var url =
                $"https://api.weixin.qq.com/card/membercard/activate?access_token={await OpenApi.GetTokenAsync(tokenOrAppId)}";
            return await HttpUtil.PostResultAsync<BaseRes>(param, url);
        }

        /// <summary>
        /// 一键激活设置激活字段
        /// </summary>
        /// <param name="accessToken"></param>
        /// <param name="param"></param>
        /// <param name="tokenOrAppId"></param>
        /// <returns></returns>
        public static async Task<BaseRes> SetActivateFormAsync(ActiveForm param, string tokenOrAppId = "")
        {
            var url =
                $"https://api.weixin.qq.com/card/membercard/activateuserform/set?access_token={await OpenApi.GetTokenAsync(tokenOrAppId)}";
            return await HttpUtil.PostResultAsync<BaseRes>(param, url);
        }
        /// <summary>
        /// 拉取会员信息接口
        /// </summary>
        /// <param name="cardId"></param>
        /// <param name="code"></param>
        /// <param name="tokenOrAppId"></param>
        /// <returns></returns>
        public static async Task<UserInfoRes> GetMemberInfoAsync(string cardId, string code, string tokenOrAppId = "")
        {
            var url =
                $"https://api.weixin.qq.com/card/membercard/userinfo/get?access_token={await OpenApi.GetTokenAsync(tokenOrAppId)}";
            var data = new { card_id = cardId, code = code };
            return await HttpUtil.PostResultAsync<UserInfoRes>(data, url);
        }
        /// <summary>
        /// 跳转型一键激活，第三步，获取用户提交资料
        /// </summary>
        /// <param name="activateTicket"></param>
        /// <param name="tokenOrAppId"></param>
        /// <returns></returns>
        public static async Task<ActivateTempInfo> GetActivateTempInfoAsync(string activateTicket, string tokenOrAppId = "")
        {
            var url =
                $"https://api.weixin.qq.com/card/membercard/activatetempinfo/get?access_token={await OpenApi.GetTokenAsync(tokenOrAppId)}";
            var data = new { activate_ticket = activateTicket };
            return await HttpUtil.PostResultAsync<ActivateTempInfo>(data, url);
        }

        /// <summary>
        /// 更新会员信息
        /// </summary>
        /// <param name="param"></param>
        /// <param name="tokenOrAppId"></param>
        /// <returns></returns>
        public static async Task<UpdateMemberRes> UpdateMemberInfoAsync(UpdateParam param, string tokenOrAppId = "")
        {
            var url =
                $"https://api.weixin.qq.com/card/membercard/updateuser?access_token={await OpenApi.GetTokenAsync(tokenOrAppId)}";
            return await HttpUtil.PostResultAsync<UpdateMemberRes>(param, url);
        }
        #endregion

        /// <summary>
        /// 更改Code接口.确保转赠后的安全性，微信允许自定义Code的商户对已下发的code进行更改。 注：为避免用户疑惑，建议仅在发生转赠行为后（发生转赠后，微信会通过事件推送的方式告知商户被转赠的卡券Code）对用户的Code进行更改。
        /// </summary>
        /// <param name="code"></param>
        /// <param name="newCode"></param>
        /// <param name="cardId"></param>
        /// <param name="tokenOrAppId"></param>
        /// <returns></returns>
        public static async Task<BaseRes> UpdateCodeAsync(string code, string newCode, string cardId, string tokenOrAppId = "")
        {
            var url = $"https://api.weixin.qq.com/card/code/update?access_token={await GetTokenAsync(tokenOrAppId)}";
            var data = new { code = code, card_id = cardId, new_code = newCode };
            return await PostResultAsync<BaseRes>(data, url);
        }

        /// <summary>
        /// 设置卡券失效接口。为满足改票、退款等异常情况，可调用卡券失效接口将用户的卡券设置为失效状态。
        /// </summary>
        /// <param name="code"></param>
        /// <param name="reason">失效理由</param>
        /// <param name="cardId">非自定义code时，此参数可以为空</param>
        /// <param name="tokenOrAppId"></param>
        /// <returns></returns>
        public static async Task<BaseRes> UnavailableAsync(string code, string reason, string cardId, string tokenOrAppId = "")
        {
            var url = $"https://api.weixin.qq.com/card/code/unavailable?access_token={await GetTokenAsync(tokenOrAppId)}";
            var data = new { card_id = cardId, code = code, reason = reason };
            return await PostResultAsync<BaseRes>(data, url);
        }
        /// <summary>
        /// 支持开发者调用该接口拉取免费券（优惠券、团购券、折扣券、礼品券）在固定时间区间内的相关数据。
        /// 查询时间区间需小于等于62天
        /// 该接口只能拉取非当天的数据，不能拉取当天的卡券数据，否则报错。
        /// </summary>
        /// <param name="beginDate">查询数据的起始时间。</param>
        /// <param name="endTime">查询数据的截至时间。</param>
        /// <param name="condSource">卡券来源，0为公众平台创建的卡券数据、1是API创建的卡券数据	</param>
        /// <param name="cardId">卡券ID。填写后，指定拉出该卡券的相关数据</param>
        /// <param name="tokenOrAppId"></param>
        /// <returns></returns>
        public static async Task<CardBizUinInfoList> GetCardBizUinInfoListAsync(DateTime beginDate, DateTime endTime, int condSource,
            string cardId = "", string tokenOrAppId = "")
        {
            var url = $"https://api.weixin.qq.com/datacube/getcardcardinfo?access_token={await GetTokenAsync(tokenOrAppId)}";
            var data = new { begin_date = beginDate.ToString("yyyy-MM-dd"), end_date = endTime.ToString("yyyy-MM-dd"), cond_source = condSource, card_id = cardId };
            return await PostResultAsync<CardBizUinInfoList>(data, url);
        }
        public static async Task<MemberCardBizuinInfoList> GetCardBizUinInfoListAsync(DateTime beginDate, DateTime endTime, int condSource,
            string tokenOrAppId = "")
        {
            var url = $"https://api.weixin.qq.com/datacube/getcardmembercardinfo?access_token={await GetTokenAsync(tokenOrAppId)}";
            var data = new { begin_date = beginDate.ToString("yyyy-MM-dd"), end_date = endTime.ToString("yyyy-MM-dd"), cond_source = condSource };
            return await PostResultAsync<MemberCardBizuinInfoList>(data, url);
        }
#endif
    }
}
